local require = require
local env = require("modules.env.env")
local log = require("modules.commhm.log")
local uu  = require("modules.commhm.utils")
local conf  = require("modules.business_common.business_config")
local share = require("modules.business_common.business_nginx_share")

local ngx = ngx
local math = math
local curr = ngx.time
local math_abs = math.abs
local table = table
local tostring = table.tostring
local tonumber = tonumber

local FOO = {
    _VERSION = '0.0.1',
    DICT_NAME = 'one_time_request',
    SHARE_TIME_OUT = 3600,
    DIFF_TIME_OUT = (env.debug == 1  or env.debug == 11) and 3600 or 300
}

local get_request_cache = function(dict_name)
    local user_md5 = ngx.md5(tostring(ngx.ctx.m_params))
    return share.get_nginx_share(dict_name, user_md5) or {}
end

local set_request_cache = function(dict_name, exptime)
    local user_md5 = ngx.md5(tostring(ngx.ctx.m_params))
    return share.set_nginx_share(dict_name, user_md5, {1}, exptime)
end

--实现逻辑 --lee 2021 08 06
--一次请求默认缓存60分钟的key, 在这个60分钟内,一次有效
--缓存失效后,根据时间来判定
--玩家倒退时间,导致与当前时间超过60分钟失效
--玩家前进时间,导致与当前时间超过60分钟也失败
--防止缓存满了后,还未到60分钟的key遭到释放,故判定的时间一定要小于缓存时间

--比如60分钟的key 在0<N<60分钟的时候遭到释放,这个时候就要靠时间去判定了
--因为如果客户端取到的是服务器时间,允许的误差在1分钟内
--如果在这1分钟内,请求成功了,那又会有60分钟的key挡住

--也许会认为有一种情况会出现刷2次的情况,就是在1分钟内请求后,key立马被释放了,然后再次发送请求,

--但实际上会被nginx下的share_dict的释放逻辑挡住,不会去释放最近的数据,所以不会出现刷2次的情况

--[[
config = {
    dict_count = 10,                    -- 分库数量
    dict_name = 'one_time_request',
    check_list = {
        ['send_order'] = 1,
        ['business_open_gift'] =1,
    }
}
--]]
FOO.check = function(cfg, act, opt)
    -- 内网测试状态跳过
    if conf.debug_env() and tonumber(ngx.ctx.m_params.test) == 1 then
        return true
    end

    local uin = ngx.ctx.m_params.uin
    local cmd = ngx.ctx.m_params.act or ngx.ctx.m_params.cmd

    opt = opt or {}
    local send_time = tonumber(opt.sendtime) or tonumber(ngx.ctx.m_params.time) or 0
    local time_out  = tonumber(opt.timeout)  or FOO.DIFF_TIME_OUT
    local time_diff = math_abs(curr() - send_time)

    -- 1. cmd 暂无timeout检查要求
    -- 2. 绝对值在DIFF_TIME_OUT秒内算是正常
    if not ngx.ctx.m_params.cmd and time_diff >= time_out then
        log.day_list("business_one_request", uu.table2json({
            reason = 'request_timeout',
            action = act,
            uin    = uin,
            cmd    = cmd,
            time   = send_time,
            now    = curr(),
            diff   = time_diff
        }))
        return false, "check request once timeout"
    end

    -- 缓存命中检查
    if not cfg.check_list or cfg.check_list[cmd] == 1 then
        local exptime    = tonumber(cfg.exptime)    or FOO.SHARE_TIME_OUT
        local dict_count = tonumber(cfg.dict_count) or 1
        local dict_name = cfg.dict_name .. (uin % dict_count)
        if uu.tableNotEmpty(get_request_cache(dict_name) or {}) then
            log.day_list("business_one_request", uu.table2json({
                reason = 'request_cache_existed',
                action = act,
                uin    = uin,
                cmd    = cmd,
                time   = send_time,
                now    = curr(),
                diff   = time_diff
            }))
            return false, "check request once existed"
        end

        --时间超过了默认阈值,防止多次请求,再一次丢到缓存内
        set_request_cache(dict_name, exptime)
    end

    return true
end

return FOO
